package com.blog.cloud.chat.endpoint;

import com.alibaba.fastjson2.JSONObject;
import com.blog.cloud.chat.handler.MessageHandler;
import com.blog.cloud.chat.message.chat.SendResponse;
import com.blog.cloud.chat.message.chat.SendToGroupMessage;
import com.blog.cloud.chat.message.chat.SendToSingleMessage;
import com.blog.cloud.chat.utils.WebSocketUtil;
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

@Setter
@Component
@ServerEndpoint("/chat/{userId}")
public class WebSocketServerEndPoint implements InitializingBean {

    public static final Logger logger = LoggerFactory.getLogger(WebSocketServerEndPoint.class);

    public static final Map<String, MessageHandler> handlers = new HashMap<>();

    private Session session;

    private String userId;

    /**
     * 当客户端与服务端建立连接时执行
     *
     * @param session 会话
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
        this.session = session;
        this.userId = userId;
        WebSocketUtil.addSession(session, userId);
        logger.info("[onOpen] the session has been append of {} ", userId);
    }

    /**
     * 当客户端发送消息时执行
     *
     * @param session 会话
     * @param message 发送的消息数据
     */
    @OnMessage
    public void onMessage(Session session, String message) {
        JSONObject object = JSONObject.parseObject(message);
        String body = JSONObject.toJSONString(object.get("body"));
        String type = (String) object.get("type");
        if (SendToSingleMessage.TYPE.equalsIgnoreCase(type)) {
            MessageHandler messageHandler = handlers.get(type);
            SendToSingleMessage sendToSingleMessage = JSONObject.parseObject(body, SendToSingleMessage.class);
            messageHandler.execute(session, sendToSingleMessage);
            return;
        }
        if (SendToGroupMessage.TYPE.equalsIgnoreCase(type)) {
            MessageHandler messageHandler = handlers.get(type);
            SendToGroupMessage sendToGroupMessage = JSONObject.parseObject(body, SendToGroupMessage.class);
            messageHandler.execute(session, sendToGroupMessage);
        }
    }

    /**
     * 当客户端与服务端断开连接，即客户端下线时执行
     */
    @OnClose
    public void onClose() {
        WebSocketUtil.removeSession(userId);
        logger.info("[onClose] the session has been removed of {}", userId);
    }

    /**
     * 当客户端与服务端通信过程中出现异常时执行
     *
     * @param session   会话
     * @param throwable 异常对象
     */
    @OnError
    public void onError(Session session, Throwable throwable) {
        SendResponse sendResponse = new SendResponse();
        sendResponse.setCode(400);
        sendResponse.setMsg(throwable.getMessage());
        WebSocketUtil.sendResponse(session, SendResponse.TYPE, sendResponse);
    }

    @Autowired
    private ApplicationContext applicationContext;

    @Override
    public void afterPropertiesSet() {
        applicationContext.getBeansOfType(MessageHandler.class).values().forEach(handler -> {
            handlers.put(handler.getType(), handler);
        });
    }
}
